package com.core.image.core.impl.async;

import com.core.image.core.BytePriorityNode;
import com.core.image.core.IoArgs;
import com.core.image.core.SendPacket;
import com.core.image.core.frames.*;

import java.io.Closeable;
import java.io.IOException;

/**
 * describe:
 *
 * @author 库琦
 * @date 2020/01/30
 */
public class AsyncPacketReader implements Closeable {
    private volatile  IoArgs ioArgs = new IoArgs();
    private volatile  BytePriorityNode<Frame> node;
    private volatile  int nodeSize = 0;
    private final PacketProvider provider;
    private short lastIdentifier = 0;
     AsyncPacketReader(PacketProvider provider){
        this.provider = provider;
    }
      synchronized  void cancel(SendPacket packet) {
         if (nodeSize == 0){
             return;
         }
         for (BytePriorityNode<Frame> x = node, before =  null; x != null;before = x,x = x.next){
                Frame frame = x.item;
                if (frame instanceof AbsSendPacketFrame){
                    AbsSendPacketFrame packetFrame = (AbsSendPacketFrame) frame;
                    if (packetFrame.getPacket() == packet){
                        boolean remobeable = packetFrame.abort();
                        if (remobeable){
                            removeFrame(x,before);
                            if (packetFrame instanceof SendHeaderFrame){
                                break;
                            }
                        }
                        CancelSendFrame cancelSendFrame = new CancelSendFrame(packetFrame.getBodyIdentifier());
                        appendNewFrame(cancelSendFrame);
                        provider.completedPacket(packet,false);
                            break;
                    }
                }
         }}
         boolean requestSendHeartbeatFrame(){
         synchronized (this){
             for (BytePriorityNode<Frame> x = node; x!= null;x =x.next){
                 Frame frame = x.item;
                 if (frame.getBodyType() == Frame.TYPE_COMMAND_HEARTBEAT){
                     return false;
                 }
             }
         }

         appendNewFrame(new HeartbeatSendFrame());
         return true;
         }



    private synchronized  void removeFrame(BytePriorityNode<Frame> removeNode, BytePriorityNode<Frame> before) {
      if (before == null){
          node = removeNode.next;
      }else {
            before.next = removeNode.next;
      }
      nodeSize --;
      if (node == null){
          requestTakePacket();
      }
     }

    boolean requestTakePacket() {
         synchronized (this){
         if (nodeSize >= 1){
             return true;
         }
         }
         SendPacket packet = provider.takePacket();
         if (packet != null){
             //构建头部帧
             short identifier = generateIdentifier();
             SendHeaderFrame frame = new SendHeaderFrame(identifier,packet);
             appendNewFrame(frame);
         }
         synchronized (this){
            return nodeSize != 0;
         }
    }

    private synchronized  void appendNewFrame(Frame frame) {
         BytePriorityNode<Frame> newNode = new BytePriorityNode<>(frame);
         if (node != null){
             node.appendWithPriority(newNode);
         }else {
             node = newNode;
         }
         nodeSize++;
    }

    @Override
    public synchronized void close() throws IOException {
         while (node != null){
             Frame frame = node.item;
             if (frame instanceof  AbsSendPacketFrame){
                 SendPacket packet = ((AbsSendPacketFrame )frame).getPacket();
                 provider.completedPacket(packet,false);
             }
             node = node.next;
         }

         nodeSize = 0;
         node = null;

    }
    private short generateIdentifier(){
         short identifier = ++ lastIdentifier;
         if (identifier == 255){
             lastIdentifier = 0;
         }
         return identifier;
 }
        IoArgs fillData() {
        Frame currentFrame =  getCurrentFrame();
        if (currentFrame == null){
            return null;
        }
        try {
            if (currentFrame.handle(ioArgs)){
                Frame nextFrame = currentFrame.nextFrame();
                //消费完本帧
                //尝试基于本帧构建后续帧
                if (nextFrame != null){
                    appendNewFrame(nextFrame);
                }else if (currentFrame instanceof SendEntityFrame){
                    provider.completedPacket(((SendEntityFrame)currentFrame).getPacket(),true);
                }
                popCurrentFrame();
            }
    //从链表的链头弹出。
            return ioArgs;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    private synchronized void popCurrentFrame() {
         node = node.next;
         nodeSize --;
         if (node == null){
             requestTakePacket();
         }
    }

    private Frame getCurrentFrame() {
         if (node == null){
             return null;
         }

         return node.item;
    }

    interface  PacketProvider{
        SendPacket takePacket();
        void completedPacket(SendPacket packet,boolean isSuccessed);
    }
}
